package com.sdk4.jinritemai;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sdk4.jinritemai.exception.ApiException;
import com.sdk4.jinritemai.model.bean.DoudianAccessToken;
import com.sdk4.jinritemai.model.response.DoudianAccessTokenResponse;
import com.sdk4.jinritemai.util.DoudianUtils;
import com.sdk4.jinritemai.util.WebUtils;
import com.sdk4.jinritemai.util.WebUtils.HttpResponseData;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class DefaultDoudianClient implements DoudianClient {
    protected String serverUrl;
    protected String appKey;
    protected String appSecret;
    protected String signMethod;
    protected int connectTimeout;
    protected int readTimeout;
    private String version;
    DoudianAccessToken accessToken;

    public DefaultDoudianClient(String serverUrl, String appKey, String appSecret) {
        this.signMethod = "hmac-sha256";
        this.connectTimeout = 30000;
        this.readTimeout = 30000;
        this.version = "2";
        this.appKey = appKey;
        this.appSecret = appSecret;
        this.serverUrl = serverUrl;
    }


    public String getToken(String shopId, String appKey, String secret) {
        JSONObject paramJson = new JSONObject(true);
        paramJson.put("code", " ");
        paramJson.put("grant_type", "authorization_self");
        paramJson.put("shop_id", shopId);
        Map<String, String> params = new HashMap<>();
        params.put("app_key", appKey);
        params.put("method", "token.create");
        params.put("param_json", paramJson.toJSONString());
        params.put("timestamp", DoudianUtils.getTimeString(new Date()));
        params.put("v", version);
        try {
            params.put("sign", DoudianUtils.signTopRequest(params, secret, signMethod));
            params.put("sign_method", "hmac-sha256");
            String url = createUrl(serverUrl, "token.create");
            String query = WebUtils.buildQuery(params, "UTF-8");
            String fullUrl = WebUtils.buildRequestUrl(url, new String[]{query});
            WebUtils.HttpResponseData data = WebUtils.doPost(fullUrl, new HashMap<>(0), "UTF-8", connectTimeout, readTimeout);
            return data.getBody();
        } catch (Exception e) {

        }
        return null;
    }

    public String refreshToken(String refreshToken, String appKey, String secret) {
        JSONObject paramJson = new JSONObject(true);
        paramJson.put("grant_type", "refresh_token");
        paramJson.put("refresh_token", refreshToken);
        Map<String, String> params = new HashMap<>();
        params.put("app_key", appKey);
        params.put("method", "token.refresh");
        params.put("param_json", paramJson.toJSONString());
        params.put("timestamp", DoudianUtils.getTimeString(new Date()));
        params.put("v", version);
        try {
            params.put("sign", DoudianUtils.signTopRequest(params, secret, signMethod));
            params.put("sign_method", "hmac-sha256");
            String url = createUrl(serverUrl, "token.refresh");
            String query = WebUtils.buildQuery(params, "UTF-8");
            String fullUrl = WebUtils.buildRequestUrl(url, new String[]{query});
            WebUtils.HttpResponseData data = WebUtils.doPost(fullUrl, new HashMap<>(0), "UTF-8", connectTimeout, readTimeout);
            return data.getBody();
        } catch (Exception e) {

        }
        return null;
    }

    @Override
    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    @Override
    public void setReadTimeout(int readTimeout) {
        this.readTimeout = readTimeout;
    }

    @Override
    public void setAccessToken(DoudianAccessToken accessToken) {
        this.accessToken = accessToken;
    }

    @Override
    public DoudianAccessToken getAccessToken() {
        return accessToken;
    }

    @Override
    public DoudianAccessToken getAccessToken(String refreshToken) {
        return null;
    }

    @Override
    public DoudianAccessToken codeToToken(String code) {
//        String url = String.format("%s/oauth2/access_token?app_id=%s&app_secret=%s&code=%s&grant_type=authorization_code",
//                serverUrl,
//                appKey,
//                appSecret,
//                code);
//        return createAccessToken(url);
        return null;
    }

    DoudianAccessToken createAccessToken(String url) {
        DoudianAccessToken accessToken;
        try {
            HttpResponseData data = WebUtils.doPost(url, new HashMap<>(0), "UTF-8", connectTimeout, readTimeout);
            DoudianAccessTokenResponse response = JSON.parseObject(data.getBody(), DoudianAccessTokenResponse.class);
            if (response.isSuccess()) {
                accessToken = response.getData();
                if (accessToken.getExpiresIn() != null) {
                    accessToken.setExpire(System.currentTimeMillis() + (accessToken.getExpiresIn() * 1000) - 60000);
                }
            } else {
                accessToken = new DoudianAccessToken("");
                accessToken.setError(DoudianUtils.isEmpty(response.getMessage()) ? response.getErrNo() + "" : response.getMessage());
            }
        } catch (IOException e) {
            accessToken = new DoudianAccessToken("");
            accessToken.setError("获取accessToken失败");
            accessToken.setException(e);
        }
        return accessToken;
    }

    @Override
    public <T extends DoudianResponse> T execute(DoudianRequest<T> request) throws ApiException {
        if (accessToken == null) {
            accessToken = getAccessToken();
        }
//        if (!accessToken.isValid()) {
//            accessToken = DoudianUtils.isEmpty(accessToken.getRefreshToken()) ? getAccessToken() : getAccessToken(accessToken.getRefreshToken());
//        }
//        if (!accessToken.isValid()) {
//            try {
//                T response = request.getResponseClass().newInstance();
//                response.setErrNo(4444);
//                response.setMessage("access token is invalid");
//            } catch (Exception e) {
//                throw new ApiException("API_CALL_ERROR", "接口调用失败", e);
//            }
//        }
        return execute(request, accessToken.getAccessToken());
    }

    @Override
    public <T extends DoudianResponse> T execute(DoudianRequest<T> request, String accessToken) throws ApiException {
        String paramJson = "";
        if (request.getMethod().equals("order.searchList")) {
            paramJson = DoudianUtils.createParamJsonT(request);
        } else {
            paramJson = DoudianUtils.createParamJson(request);
        }
        Map<String, String> params = new HashMap<>();
        params.put("method", request.getMethod());
        params.put("app_key", appKey);
        params.put("param_json", paramJson);
        params.put("timestamp", DoudianUtils.getTimeString(new Date()));
        params.put("v", version);

        try {
            params.put("sign", DoudianUtils.signTopRequest(params, appSecret, signMethod));
            params.put("sign_method", signMethod);
            params.put("access_token", accessToken);

            String url = createUrl(serverUrl, request.getMethod());
            String query = WebUtils.buildQuery(params, "UTF-8");
            String fullUrl = WebUtils.buildRequestUrl(url, new String[]{query});
            HttpResponseData data = WebUtils.doPost(fullUrl, new HashMap<>(0), "UTF-8", connectTimeout, readTimeout);

            T result = JSON.parseObject(data.getBody(), request.getResponseClass());
            if (result != null) {
                result.setAppKey(appKey);
            }
            return result;
        } catch (IOException e) {
            throw new ApiException("API_CALL_ERROR", "接口调用失败", e);
        }
    }

    static String createUrl(String baseUrl, String method) {
        StringBuilder url = new StringBuilder();
        if (DoudianUtils.isNotEmpty(baseUrl)) {
            url.append(baseUrl);
            if (!baseUrl.endsWith("/")) {
                url.append('/');
            }
        }
        if (DoudianUtils.isNotEmpty(method)) {
            url.append(method.replace('.', '/'));
        }
        return url.toString();
    }

}
